package com.myrpc.consumer.rpc.proxy;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Proxy;

/**
 * Spring 中有两种类型的Bean，一种是普通Bean，另一种是工厂Bean 即 FactoryBean。FactoryBean跟普通Bean不同，
 * 其返回的对象不是指定类的一个实例，而是该FactoryBean的getObject方法所返回的对象。
 * 应用场景
  FactoryBean 通常是用来创建比较复杂的bean，一般的bean 直接用xml配置即可，
	但如果一个bean的创建过程中涉及到很多其他的bean 和复杂的逻辑，用xml配置比较困难，这时可以考虑用FactoryBean。
	特别适合动态代理加载  FactoryBean始化 Bean 时就会调用 getObject 方法
 */
public class RpcFactoryBean<T> implements FactoryBean<T> {

    private Class<T> rpcInterface;

    @Autowired
    RpcFactory<T> factory;

    public RpcFactoryBean() {}

    /**
     *  rpcInterface 实例化 RpcFactoryBean
     * @param rpcInterface
     */
    public RpcFactoryBean(Class<T> rpcInterface) {
        this.rpcInterface = rpcInterface;
    }

    /**
     * 重要：：：
     * 如果该 Bean 未实现 FactoryBean 接口，则直接返回该Bean实例；
     * 如果该 Bean 实现了 FactoryBean 接口，则会返回的实例是 getObject() 返回值。
     */
    public T getObject() throws Exception {
        return getRpc();
    }

    public Class<?> getObjectType() {
        return this.rpcInterface;
    }

    public boolean isSingleton() {
    	//是否单例
        return true;
    }

    /**
     * JDK 动态代理，当调用 rpcInterface 接口的方法时，会走 factory 的 invoke 方法
     * @param <T>
     * @return
     */
    public <T> T getRpc() {
        return (T) Proxy.newProxyInstance(rpcInterface.getClassLoader(), new Class[] { rpcInterface },factory);
    }
}
